#   This script contains my first try of 
#   learning manim's new shaders version

from math import degrees
from os import replace, write
import numpy as np
from manimlib import *

class InteractiveDevelopment(Scene) :
    def construct(self):
        circle = Circle()
        circle.set_fill(BLUE, opacity=0.3)
        circle.set_stroke(BLUE_E, width=4)
        square = Square()

        self.play(ShowCreation(square))
        self.wait(2)
        self.play(ReplacementTransform(square, circle))

        # self.embed()

        # self.play(circle.animate.shift(2*UP).scale(0.25))
        self.play(circle.shift,UP*2, circle.scale,0.25)

        text = Text("""
            In general, using the interactive shell
            is very helpful when developing new scenes
            """, size=30)
        
        self.play(Write(text))

        return super().construct()

class AnimatingMethods(Scene) :
    def construct(self):
        gird = Tex(r"\pi").get_grid(10, 10, height=4)
        self.play(ShowCreation(gird))
        
        self.play(gird.animate.shift(LEFT))
        self.play(gird.shift, LEFT)

        self.play(gird.animate.set_color(YELLOW))
        self.wait()
        self.play(gird.animate.set_submobject_colors_by_gradient(BLUE, GREEN))
        self.wait()
        self.play(gird.animate.set_height(TAU - MED_SMALL_BUFF))
        self.wait()
        
        self.play(gird.animate.apply_complex_function(np.exp), run_time=5)
        self.wait()

        return super().construct()

class TextExample(Scene) :
    def construct(self):
        text = Text("My first text", font="Consolas", font_size=50)
        # self.play(Write(text))
        difference = Text(
            """
            The most important difference between Text and TexText is that\n
            you can change the font more easily, but can't use the LaTeX grammar
            """,
            font="Arial", font_size=24,
            t2c={"Text": BLUE, "TexText": RED, "LaTeX": ORANGE}
        )
        VGroup(text, difference).arrange(DOWN, buff=1)
        self.play(Write(text))
        self.play(FadeIn(difference, UP))
        self.wait(3)
        
        fonts = Text(
            "And you can also set the font according to different words",
            font="Arial",
            t2f={'font': "consoalas", "words": "Consolas"},
            t2c={"font": BLUE, "words":ORANGE}
        )
        self.play(Write(fonts))

        return super().construct()

class TexTransformExample(Scene):
    def construct(self):
        to_isolate = ['B', 'C', '=', '(', ')']
        lines = VGroup(
            Tex("A^2", "+", "B^2", "=", "C^2"),
            Tex("A^2", "=", "C^2", "-", "B^2"),
            Tex("A^2 = (C + B)(C - B)", isolate=["A^2", *to_isolate]),
            Tex("A = \\sqrt{(C + B)(C - B)}", isolate=["A", *to_isolate])
        )
        lines.arrange(DOWN, buff=LARGE_BUFF)

        for line in lines :
            line.set_color_by_tex_to_color_map({
                "A": BLUE,
                "B": TEAL,
                "C": GREEN
            })
        
        self.add(lines[0])

        self.play(
            TransformMatchingTex(
                lines[0].copy(), lines[1],
                path_arc=90*DEGREES,
            ),
            run_time=2
        )

        self.play(
            TransformMatchingTex(
                lines[1].copy(), lines[2],
                play_arc=90*DEGREES
            ),
            run_time=2
        )

        self.play(FadeOut(lines[2]))
        self.play(
            TransformMatchingTex(
                lines[1].copy(), lines[2],
                play_arc=90*DEGREES,
                key_map={
                    "C^2": "C",
                    "B^2": "B"
                }
            ),
            run_time=2
        )
        self.wait()

        new_line2 = Tex("A^2 = (C + B)(C - B)", isolate=["A", *to_isolate])
        new_line2.replace(lines[2])
        new_line2.match_style(lines[2])
        self.wait()

        self.play(
            TransformMatchingTex(
                new_line2, lines[3],
                transform_mismatches=True,
            ),
            run_time=2
        )

        self.wait()
        
        self.play(FadeOut(lines, RIGHT))

        source = Text("the morse code", height=1)
        target = Text("here come dots", height=1)

        self.play(Write(source))
        self.wait()
        kw = {"run_time": 3, "path_arc": PI / 2}

        self.play(TransformMatchingShapes(source, target, **kw))
        self.wait()
        self.play(TransformMatchingShapes(target, source, **kw))
        self.wait()

        return super().construct()

class UpdatersExample(Scene) :
    def construct(self):
        square = Square()
        square.set_fill(BLUE_E, 1)
        
        brace = always_redraw(Brace, square, UP)

        text, number = label = VGroup(
            Text("Width="),
            DecimalNumber(
                0,
                show_ellipsis=True,
                num_decimal_places=2,
                include_sign=True,
            )
        )

        label.arrange(RIGHT)
        
        always(label.next_to, brace, UP)
        f_always(number.set_value, square.get_width)

        self.add(brace, square, label)

        self.play(
            square.animate.scale(2),
            rate_func=there_and_back,
            run_time=3
        )
        self.wait()
        self.play(square.animate.set_width(5, stretch=True), run_time=3)
        self.wait()
        self.play(square.animate.set_width(2, stretch=True), run_time=3)

        now=self.time
        w0=square.get_width()
        square.add_updater(
            lambda m: m.set_width(w0*math.cos(self.time-now)+w0)
        )
        self.wait(4*PI)
        
        return super().construct()

class CoordinateSystemExample(Scene):
    def construct(self):
        axes = Axes(
            x_range=(-1, 10),
            y_range=(-2, 2, 0.5),
            height=6,
            width=10,
            axis_config={
                "stroke_color": GREY_A,
                "stroke_width": 2,
            },
            y_axis_config={
                "include_tip": False
            }
        )
        axes.add_coordinate_labels(
            font_size=20,
            num_decimal_places=1
        )
        
        self.add(axes)

        dot=Dot(color=RED)
        dot.move_to(axes.c2p(0, 0))
        self.play(FadeIn(dot, scale=0.5))
        self.play(dot.animate.move_to(axes.c2p(3, 2)))
        self.wait()
        self.play(dot.animate.move_to(axes.c2p(5, 0.5)))
        self.wait()
        # self.play(ShowCreation(axes))

        h_line=always_redraw(lambda:axes.get_h_line(dot.get_left()))
        v_line=always_redraw(lambda:axes.get_v_line(dot.get_bottom()))
        self.play(
            ShowCreation(h_line),
            ShowCreation(v_line)
        )
        self.play(dot.animate.move_to(axes.c2p(3, -2)))
        self.wait()
        self.play(dot.animate.move_to(axes.c2p(1, 1)))
        self.wait()

        f_always(dot.move_to, lambda: axes.c2p(1, 1))
        self.play(
            axes.animate.scale(0.75).to_corner(UL),
            run_time=2
        )
        self.wait()
        return super().construct()

class GraphExample(Scene):
    def construct(self):
        axes = Axes(
            x_range=(-3, 10),
            y_range=(-1, 8)
        )
        axes.add_coordinate_labels()
        
        self.play(ShowCreation(axes))

        sin_graph = axes.get_graph(
            lambda x: 2*math.sin(x),
            color=BLUE
        )

        relu_graph = axes.get_graph(
            lambda x: max(x, 0),
            use_smoothing=False,
            color=GREEN
        )

        step_graph = axes.get_graph(
            lambda x: 2.0 if x>3 else 1.0,\
                discontinuities=[3],
                color=GREEN
        )
        sin_label = axes.get_graph_label(sin_graph, "\\sin(x)")
        relu_label = axes.get_graph_label(relu_graph, "relu")
        step_label = axes.get_graph_label(step_graph, "step")

        self.play(
            ShowCreation(sin_graph),
            FadeIn(sin_label)
        )
        self.wait(2)

        self.play(
            ReplacementTransform(sin_graph, relu_graph),
            FadeTransform(sin_label, relu_label)
        )
        self.wait(2)
        
        self.play(
            ReplacementTransform(relu_graph, step_graph),
            FadeTransform(relu_label, step_label)
        )
        self.wait(2)
        
        parabola = axes.get_graph(lambda x: 0.25 * x**2)
        parabola.set_stroke(BLUE)
        self.play(
            FadeOut(step_graph),
            FadeOut(step_label),
            ShowCreation(parabola)
        )
        self.wait()

        dot=Dot(color=RED)
        dot.move_to(axes.i2gp(2, parabola))
        self.play(FadeIn(dot, scale=0.5))

        x_tracker = ValueTracker(2)
        f_always(dot.move_to,lambda: axes.i2gp(x_tracker.get_value(), parabola))

        self.play(x_tracker.animate.set_value(4), run_time=3)
        self.play(x_tracker.animate.set_value(-1), run_time=3)
        self.wait()
        return super().construct()

class trying(Scene) :
    def construct(self):
        text=Text("Helloworld")
        self.play(Write(text))
        return super().construct()
